package guru.merlin.bus;

//import guru.merlin.core.CantHandException_;
import guru.merlin.core.CantHandException;
import guru.merlin.core.Envelope;
import guru.merlin.core.EnvelopeHandler;
import guru.merlin.core.Route;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.log4j.Logger;

/**
 * 
 * @author Cesar Obach-Renner, cesar@guru.com.ve
 */
public class EnvelopeBus implements EnvelopeHandler{
    private Map outboundQueues = new HashMap();
    private Map inboundQueues = new HashMap();
    private Map handlers = new HashMap();
    static Logger logger = Logger.getLogger(EnvelopeBus.class);

    /**
     * Instancia el MsgBus registrando un consumidor/procesador de la capa <i>layerId </i>
     */
    public EnvelopeBus() {
    }

    public void connectHandler(EnvelopeHandler handler, Route route) throws MessagingInfrastructureException, RouteAlreadyHandledException {
        try {

            if (inboundQueues.containsKey(route)) { throw new RouteAlreadyHandledException("route:" + route); }

            handlers.put(handler, route);
            inboundQueues.put(route, new JMSQueue(route.toString(), handler));
        } catch (Exception e) {
            throw new MessagingInfrastructureException(e + "");
        }
    }

    public void disconnectHandler(EnvelopeHandler handler) throws HandlerNotFoundException, MessagingInfrastructureException {
        Route route;
        UVQueue queue;

        if ((route = (Route) handlers.remove(handler)) == null) { throw new HandlerNotFoundException(""); }
        queue = (UVQueue) inboundQueues.remove(route);
        try {
            queue.finalize();
        } catch (Exception e) {
            throw new MessagingInfrastructureException(e + "");
        } finally {

        }
    }

    public void start() throws MessagingInfrastructureException {
        try {
            for (Iterator iter = inboundQueues.values().iterator(); iter.hasNext();) {
                ((UVQueue) iter.next()).start();
            }
        } catch (Exception e) {
            throw new MessagingInfrastructureException(e + "");
        } finally {

        }
    }

    public void stop() throws MessagingInfrastructureException {
        try {
            for (Iterator iter = inboundQueues.values().iterator(); iter.hasNext();) {
                ((JMSQueue) iter.next()).stop();
            }
        } catch (Exception e) {
            throw new MessagingInfrastructureException(e + "");
        } finally {

        }

    }
    
        public void stop(Route route) throws MessagingInfrastructureException {
        try {
            String routeName = route.toString().trim ();
            JMSQueue jmsQueue = null;
            for (Iterator iter = inboundQueues.values().iterator(); iter.hasNext();) {
                jmsQueue = (JMSQueue) iter.next();
                logger.info ("stoping queue connection..."+routeName);
                if (routeName.equalsIgnoreCase (jmsQueue.queueName)) {
                    jmsQueue.queueConnection.stop ();
                }
                logger.info ("queue connection "+routeName+" stoped");                
            }
        } catch (Exception e) {
            throw new MessagingInfrastructureException(e + "");
        } finally {

        }
    }

    public void start(Route route) throws MessagingInfrastructureException {
        try {
            String routeName = route.toString().trim ();
            JMSQueue jmsQueue = null;
            for (Iterator iter = inboundQueues.values().iterator(); iter.hasNext();) {
                jmsQueue = (JMSQueue) iter.next();
                logger.info ("starting queue connection..."+routeName);
                if (routeName.equalsIgnoreCase (jmsQueue.queueName)) {
                    jmsQueue.queueConnection.start ();
                }
                logger.info ("queue connection "+routeName+" started");                
            }
        } catch (Exception e) {
            throw new MessagingInfrastructureException(e + "");
        } finally {

        }
    }        

    public Object handEnvelope(Envelope envelope) throws CantHandException {
        UVQueue queue;
        String layerId;
        try {
            layerId = envelope.getDestinationRoute().toString();
            if ((queue = (UVQueue) outboundQueues.get(layerId)) == null) {
                outboundQueues.put(layerId, queue = new JMSQueue(layerId));
            }

            queue.send(envelope);
            logger.info("Envelope in the queue:" + envelope.getId());
        } catch (Exception e) {
            throw new CantHandException(e + "");
        } finally {

        }
        return envelope;
    }

    public void finalize() throws MessagingInfrastructureException {
        try {
            for (Iterator iter = inboundQueues.values().iterator(); iter.hasNext();) {
                ((UVQueue) iter.next()).finalize();
            }

            for (Iterator iter = outboundQueues.values().iterator(); iter.hasNext();) {
                ((UVQueue) iter.next()).finalize();
            }
        } catch (Exception e) {
            throw new MessagingInfrastructureException(e + "");
        } finally {

        }
    }

    /**
     * @param EnvelopeReference
     * @throws CantHandException
     */
    public void retrieveEnvelope(Object EnvelopeReference) throws CantHandException {
    }

    /**
     * Hace persistente el procesamientos de un objeto Envelope.
     * 
     * @param EnvelopeReference.
     *            Referencia al Envelope que fue procesado.
     * @throws CantHandException
     */
    public void commitHandEnvelope(Object EnvelopeReference) throws CantHandException {
    }

}